local function GetStringsTable()
    return TUNING.NPC_CHAT_TABLE[ type(TUNING.__NPC_LANGUAGE)=="function" and TUNING.__NPC_LANGUAGE() or TUNING.__NPC_LANGUAGE ] ["npc_item_magic_tophat"] or {}
end
local function _onunequip(inst, owner)
    local skin_build = inst:GetSkinBuild()
    if skin_build ~= nil then
        owner:PushEvent("unequipskinneditem", inst:GetSkinName())
    end

    owner.AnimState:ClearOverrideSymbol("headbase_hat") --it might have been overriden by _onequip
    if owner.components.skinner ~= nil then
        owner.components.skinner.base_change_cb = owner.old_base_change_cb
    end

    owner.AnimState:ClearOverrideSymbol("swap_hat")
    owner.AnimState:Hide("HAT")
    owner.AnimState:Hide("HAIR_HAT")
    owner.AnimState:Show("HAIR_NOHAT")
    owner.AnimState:Show("HAIR")

    if owner:HasTag("player") then
        owner.AnimState:Show("HEAD")
        owner.AnimState:Hide("HEAD_HAT")
    end
end
local function top_hidefx(inst)
    if inst.fx ~= nil then
        inst.fx:Remove()
        inst.fx = nil
    end
end
local function top_showfx_onground(inst)
    if inst.fx == nil then
        inst.fx = SpawnPrefab("tophat_shadow_fx")
    else
        inst.fx.Follower:StopFollowing()
        inst.fx.Transform:SetPosition(0, 0, 0)
    end
    inst.fx.entity:SetParent(inst.entity)
end
local function _onequip(inst, owner, symbol_override, headbase_hat_override)
    local skin_build = inst:GetSkinBuild()
    if skin_build ~= nil then
        owner:PushEvent("equipskinneditem", inst:GetSkinName())
        owner.AnimState:OverrideItemSkinSymbol("swap_hat", skin_build, symbol_override or "swap_hat", inst.GUID, "hat_top")
    else
        owner.AnimState:OverrideSymbol("swap_hat", "hat_top", symbol_override or "swap_hat")
    end
    
    owner.AnimState:ClearOverrideSymbol("headbase_hat") --clear out previous overrides
    if headbase_hat_override ~= nil then
        local skin_build = owner.AnimState:GetSkinBuild()
        if skin_build ~= "" then
            owner.AnimState:OverrideSkinSymbol("headbase_hat", skin_build, headbase_hat_override )
        else 
            local build = owner.AnimState:GetBuild()
            owner.AnimState:OverrideSymbol("headbase_hat", build, headbase_hat_override)
        end
    end

    owner.AnimState:Show("HAT")
    owner.AnimState:Show("HAIR_HAT")
    owner.AnimState:Hide("HAIR_NOHAT")
    owner.AnimState:Hide("HAIR")

    if owner:HasTag("player") then
        owner.AnimState:Hide("HEAD")
        owner.AnimState:Show("HEAD_HAT")
    end
    if inst.skin_equip_sound and owner.SoundEmitter then
        owner.SoundEmitter:PlaySound(inst.skin_equip_sound)
    end
end
local function top_showfx_equipped(inst, owner)
    if inst.fx == nil then
        inst.fx = SpawnPrefab("tophat_shadow_fx")
    end
    inst.fx.entity:SetParent(owner.entity)
    inst.fx.Follower:FollowSymbol(owner.GUID, "swap_hat", 0, -100, 0)
end
local function onequip(inst, owner)
    _onequip(inst, owner)
    top_showfx_equipped(inst, owner)
end
local function onunequip(inst, owner)
    _onunequip(inst, owner)
    if inst:IsInLimbo() then
        top_hidefx(inst)
    else
        top_showfx_onground(inst)
    end
end
-- local function top_onclose(tophatcontainer)
--     tophatcontainer.tophat.components.magiciantool:StopUsing()
-- end
local function top_onstartusing(inst, doer)
    -- local owner = inst.npc_base_lib:Get_Owner()   
end

local function top_onstopusing(inst, doer)
end

local function top_enterlimbo(inst, owner)
    if not inst.components.equippable:IsEquipped() then
        top_hidefx(inst)
    end
end

local function top_exitlimbo(inst)
    if not inst.components.equippable:IsEquipped() then
        top_showfx_onground(inst)
    end
end

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
----- 添加和注册容器界面
local function container_Widget_change(theContainer)
    -----------------------------------------------------------------------------------
    ----- 容器界面名 --- 要独特一点，避免冲突
    local container_widget_name = "npc_item_magic_tophat_widget"

    -----------------------------------------------------------------------------------
    ----- 检查和注册新的容器界面
    local all_container_widgets = require("containers")
    local params = all_container_widgets.params
    if params[container_widget_name] == nil then
        params[container_widget_name] = {
            widget =
            {
                slotpos = {},
                animbank = "ui_fish_box_5x4",
                animbuild = "ui_fish_box_5x4",
                pos = Vector3(0, 220, 0),
                side_align_tip = 160,
            },
            type = "chest",
            acceptsstacks = true,                
        }

        for y = 2.5, -0.5, -1 do
            for x = -1, 3 do
                table.insert(params[container_widget_name].widget.slotpos, Vector3(75 * x - 75 * 2 + 75, 75 * y - 75 * 2 + 75, 0))
            end
        end
        ------------------------------------------------------------------------------------------
        ---- item test
            params[container_widget_name].itemtestfn =  function(container_com, item, slot)
                return container_com and container_com.inst and item ~= container_com.inst
            end
        ------------------------------------------------------------------------------------------
    end

    theContainer:WidgetSetup(container_widget_name)
    ------------------------------------------------------------------------
end
local function add_container_before_not_ismastersim_return(inst)
    ------ 添加背包container组件    --- 必须在 SetPristine 之后，
    -- local container_WidgetSetup = "wobysmall"
    if TheWorld.ismastersim then
        inst:AddComponent("container")
        inst.components.container.openlimit = 1  ---- 限制1个人打开
        -- inst.components.container:WidgetSetup(container_WidgetSetup)
        container_Widget_change(inst.components.container)

    else
        inst.OnEntityReplicated = function(inst)
            container_Widget_change(inst.replica.container)
        end
    end
end
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

local function DeletFX(inst)
    if inst._star_door then
        inst._star_door:PushEvent("Set",{
            disappear_anim_speed_mult = 30,
            disappear = true
        })
        inst._star_door = nil
    end
end
local function SpawnFX(inst)
    if inst._star_door then
        inst._star_door:Remove()
        inst._star_door = nil
    end
    local owner = inst.npc_base_lib:Get_Owner()
    if owner == nil then
        return
    end
    local pt = Vector3(inst.Transform:GetWorldPosition())
    local fx = SpawnPrefab("npc_fx_star_door")
    -- local fx = owner:SpawnChild("npc_fx_star_door")
    fx:PushEvent("Set",{
            pt = pt,
            scale = Vector3(2,2,2),
            appear = true,

            appear_anim_speed_mult = 30,
            idle_anim_speed_mult = 5,
            disappear_anim_speed_mult = 30,

            layer = LAYER_WORLD_BACKGROUND,
            orientation = ANIM_ORIENTATION.OnGround,
            sort = 0,
        })
    
    inst._star_door = fx
    fx.check_player_task = fx:DoPeriodicTask(0.5,function()
        if inst.npc_base_lib:Distance_Targets(fx,inst) > 2.5 and fx.check_player_task then
            fx.check_player_task:Cancel()
            fx.check_player_task = nil
            DeletFX(inst)
            if inst.components.container and inst.components.container:IsOpen() then
                inst.components.container:Close()
                local owner = inst.npc_base_lib:Get_Owner()
                if owner and owner:HasTag("player") then
                    onequip(inst,owner)
		            owner:PushEvent("equip", { item = inst, eslot = EQUIPSLOTS.HEAD})

                end
            end
        end        
    end)
end

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
local function fn()
    local inst = CreateEntity()

    inst.entity:AddTransform()
    inst.entity:AddAnimState()
    inst.entity:AddSoundEmitter()
    inst.entity:AddNetwork()

    MakeInventoryPhysics(inst)

    inst.AnimState:SetBank("tophat")
    inst.AnimState:SetBuild("hat_top")
    inst.AnimState:PlayAnimation("anim")

    inst:AddTag("hat")
    inst:AddTag("nosteal")
    inst:AddTag("npc_item_skin")
    inst:AddTag("waterproofer")
    inst:AddTag("fridge")
    inst:AddTag("npc_item_magic_tophat")
    inst:AddTag("npc_no_random_skin")

    inst.entity:SetPristine()
    add_container_before_not_ismastersim_return(inst)
    inst.prefab_base = "tophat"
    if not TheWorld.ismastersim then
        return inst
    end

    inst:AddComponent("npc_base_lib")
    inst:AddComponent("npc_everything_data")

    inst.components.container.canbeopened = false

    -- inst:ListenForEvent("reskin",function(inst,_table)
    --     if _table and _table.doer then
    --         inst.npc_base_lib:Change_Item_Skin(_table.doer,inst)
    --         return
    --     end
    --     inst.npc_base_lib:Change_Item_Skin(inst)
    -- end)
    inst.npc_base_lib:Add_Reskin_Event()


    inst:AddComponent("inspectable")
    inst:AddComponent("named")
    inst:AddComponent("inventoryitem")
    inst.components.inventoryitem:ChangeImageName("tophat")

    inst.components.named:SetName(GetStringsTable().name)
    STRINGS.CHARACTERS.GENERIC.DESCRIBE[string.upper("npc_item_magic_tophat")] = GetStringsTable().inspect_str  --人物检查的描述

    inst:AddComponent("equippable")
    inst.components.equippable:SetOnEquip(onequip)
    inst.components.equippable:SetOnUnequip(onunequip)
    inst.components.equippable.equipslot = EQUIPSLOTS.HEAD
    -- inst.components.equippable.dapperness = -TUNING.CRAZINESS_MED*2
    inst.components.equippable.dapperness = 0
    inst.components.equippable.is_magic_dapperness = true

    inst:AddComponent("waterproofer")
    inst.components.waterproofer:SetEffectiveness(TUNING.WATERPROOFNESS_SMALL*3)

    -------------------------------------------------------------------------
    -- -- 在物品栏里带特效的图标需要这个组件
    inst:AddComponent("magiciantool")
    inst.components.magiciantool:SetOnStartUsingFn(top_onstartusing)
    inst.components.magiciantool:SetOnStopUsingFn(top_onstopusing)
    inst:ListenForEvent("enterlimbo", top_enterlimbo)
    inst:ListenForEvent("exitlimbo", top_exitlimbo)
    -------------------------------------------------------------------------


    local owner = inst.components.equippable:IsEquipped() and inst.components.inventoryitem.owner or nil
    if owner ~= nil then
        top_showfx_equipped(inst, owner)
    elseif not inst:IsInLimbo() then
        top_showfx_onground(inst)
    end
    -----------------------------------------------------------------------------
    -- inst.components.container.canbeopened = false
    inst:ListenForEvent("equipped",function(inst,_table)
        -- inst.components.container.canbeopened = true
        if _table and _table.owner and _table.owner:HasTag("player") and _table.owner.components.playercontroller then
            local owner = _table.owner
            inst:AddComponent("npc_components_magic_item")
            inst.components.container.canbeopened = true
            
            owner:ListenForEvent("newstate",inst.__cursed_monkey_sg_new_state_task)

            ---------------------------------------------------------------------------
            ---- 处理玩家打开帽子期间，又穿戴了另外一个帽子，导致奇怪的显示问题。
            
            owner.npc_base_lib._______npc_magic_tophat_event = owner.npc_base_lib._______npc_magic_tophat_event or function(owner,_cmd_table)
                -- print("info _______npc_magic_tophat_event",_cmd_table and _cmd_table.eslot)
                if owner and owner.sg and _cmd_table and _cmd_table.item and _cmd_table.item == inst and not owner.sg:HasStateTag("dead") then
                    -- owner:DoTaskInTime(0,function()
                        owner.sg:GoToState("idle")
                    -- end)
                    owner:RemoveEventCallback("unequip",owner.npc_base_lib._______npc_magic_tophat_event)
                end
            end
            owner:ListenForEvent("unequip",owner.npc_base_lib._______npc_magic_tophat_event)
            

            ---------------------------------------------------------------------------

        end
    end)
    inst:ListenForEvent("unequipped",function(inst,_table)
        -- inst.components.container.canbeopened = false  
        if _table and _table.owner and _table.owner:HasTag("player") and _table.owner.components.playercontroller then
            local owner = _table.owner
            if  owner.sg and not ( owner.sg:HasStateTag("busy") or owner.sg:HasStateTag("doing") or  owner.sg:HasStateTag("dead")  ) then
                owner.sg:GoToState("idle")
            end
            owner:RemoveEventCallback("newstate",inst.__cursed_monkey_sg_new_state_task)

        end
        inst:RemoveComponent("npc_components_magic_item")
        inst.components.container.canbeopened = false
        inst.components.container:Close()
    end)

    inst.__cursed_monkey_sg_new_state_task = function(player,_table)
        local monkey_state = {
            ["changetomonkey"] = true,
            ["changetomonkey_pst"] = true,
            ["changefrommonkey"] = true,
            ["changefrommonkey_pst"] = true,
        }
        if type(_table) == "table" and monkey_state[_table.statename] then
            player.components.inventory:Unequip(EQUIPSLOTS.HEAD)
            player.components.inventory:GiveItem(inst)
        end
    end


    -- inst:DoTaskInTime(0,function()
    --     -- if inst.npc_everything_data:Get("create_reskin_flag") ~= true then
    --     --     inst.npc_base_lib:Change_Item_Skin(inst)
    --     --     inst.npc_everything_data:Set("create_reskin_flag",true)
    --     -- end
    --     -- if inst.npc_everything_data:Get("onbuild_test_flag") ~= true then
    --     --     inst.npc_base_lib:Announce(GetStringsTable().announce)
    --     --     inst.npc_everything_data:Set("onbuild_test_flag",true)
    --     -- end
    -- end)

    inst:ListenForEvent("onopen",SpawnFX)
    inst:ListenForEvent("onclose",DeletFX)
    inst.OnBuiltFn = function(inst,builder)
        if builder and builder.npc_everything_data and builder.npc_everything_data:Get("npc_item_magic_tophat.first_time_buy_announce") ~= true then
            builder.npc_base_lib:Wisper(GetStringsTable().announce)
            builder.npc_everything_data:Set("npc_item_magic_tophat.first_time_buy_announce",true)
        end
    end
    -----------------------------------------------------------------------------

    MakeHauntableLaunch(inst)
    return inst
end

return Prefab("npc_item_magic_tophat", fn)
